/*
  author Sylvain Bertrand <digital.ragnarok@gmail.com>
  Protected by GNU Affero GPL v3 with some exceptions.
  See README at root of alga tree.
*/
#include <linux/device.h>
#include <linux/i2c.h>

#include <alga/alga.h>
#include <alga/pixel_fmts.h>
#include <alga/timing.h>
#include <alga/dp.h>
#include <alga/amd/atombios/atb.h>
#include <alga/amd/atombios/dce.h>
#include <alga/amd/dce4/dce4.h>
#include <alga/amd/dce4/dce4_dev.h>

#include "dce4.h"

int dpcd_wr(struct dce4 *dce, unsigned i, u16 addr, u8 byte)
{
	int r;

	r = atb_dp_aux_native_write(dce->ddev.atb, dce->dps[i].atb_aux_i2c_id,
					dce->dps[i].hpd, addr, &byte, 1);
	if (r <= 0)
		return -DCE4_ERR;
	return 0;
}

int dpcd_lanes_vs_pre_emph_wr(struct dce4 *dce, unsigned i, u8 vs_pre_emph)
{
	int r;
	u8 lanes_training_set[DP_MAX_LANES_N];

	memset(lanes_training_set, vs_pre_emph, dce->dps[i].lanes_n);

	r = atb_dp_aux_native_write(dce->ddev.atb, dce->dps[i].atb_aux_i2c_id,
		dce->dps[i].hpd, DPCD_TRAINING_LANE0_SET, lanes_training_set,
							dce->dps[i].lanes_n);
	if (r < dce->dps[i].lanes_n) {
		dev_err(dce->ddev.dev, "dce4:dp%u:link training: unable to "
			"dpcd write vs and pre emph for dp sink\n", i);
		return -DCE4_ERR;
	}
	return 0;
}

int dpcd_link_status(struct dce4 *dce, unsigned i, u8 *link_status)
{
	int r;

	r = atb_dp_aux_native_read(dce->ddev.atb, dce->dps[i].atb_aux_i2c_id,
			dce->dps[i].hpd, DPCD_LANE0_1_STATUS, link_status,
							DPCD_LINK_STATUS_SZ);
	if (r < DPCD_LINK_STATUS_SZ) {
		dev_err(dce->ddev.dev, "dce4:dp%u:link training: unable to read"
							"link status\n", i);
		return -DCE4_ERR;
	}
	return 0;
}

int dpcd_info(struct dce4 * dce, unsigned i)
{
	struct dp *dp;
	int r;

	dp = &dce->dps[i];

	memset(dp->dpcd_info, 0, sizeof(dp->dpcd_info));
	r = atb_dp_aux_native_read(dce->ddev.atb, dp->atb_aux_i2c_id, dp->hpd,
				DPCD_REV, dp->dpcd_info, sizeof(dp->dpcd_info));
	if (r <= 0)
		return -DCE4_ERR;

	dev_info(dce->ddev.dev, "dce4: dp%u dpcd=0x%02x 0x%02x 0x%02x 0x%02x "
		"0x%02x 0x%02x 0x%02x 0x%02x\n", i, dp->dpcd_info[0],
		dp->dpcd_info[1], dp->dpcd_info[2], dp->dpcd_info[3],
		dp->dpcd_info[4], dp->dpcd_info[5], dp->dpcd_info[6],
							dp->dpcd_info[7]);
	return 0;
}
